---
title: Operations and processes
summary: End-to-end processing workflows behind PdfAPI's endpoint surface.
status: draft
owner: Not determined from source
last_reviewed: 2026-09-17
library: PdfAPI
reference_type: embedded
---

# Operations and processes

PdfAPI performs 13 distinct operations behind its 13 endpoints: document conversion, merging, page extraction, tracking-record persistence and polling, tracked-document download, and six stateless PDF inspection/validation checks. This page is the operation catalog and hub; each operation's step-by-step logic lives in its own page under `operations/`.

## Operation catalog

| ID | Operation | Entry endpoint | Trigger | Owning component | Rules |
| --- | --- | --- | --- | --- | --- |
| [OP-CONVERT-REQUEST](operations/op-convert-request.md) | Convert (request-shaped) | [`POST v1/convert`](endpoints/convert-controller.md#post-v1%2Fconvert) | Client submits a `ConvertRequest` body | `ConvertController.Convert(ConvertRequest)` | [BR-PDFAPI-003](business-rules.md#br-pdfapi-003-processor-selection-by-configuration), [BR-PDFAPI-008](business-rules.md#br-pdfapi-008-unsupported-extension-leaves-status-at-default), [BR-PDFAPI-009](business-rules.md#br-pdfapi-009-plain-text-double-conversion), [BR-PDFAPI-010](business-rules.md#br-pdfapi-010-tracking-forced-on-with-heat-email), [BR-PDFAPI-016](business-rules.md#br-pdfapi-016-save-input-to-temp-storage), [BR-PDFAPI-017](business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult), [BR-PDFAPI-019](business-rules.md#br-pdfapi-019-skip-conversion-when-input-is-already-pdf), [BR-PDFAPI-020](business-rules.md#br-pdfapi-020-activepdf-retry-behavior) |
| [OP-CONVERT-FILE](operations/op-convert-file.md) | Convert (file-shaped) | [`POST v1/convert/{fileExtension}`](endpoints/convert-controller.md#post-v1%2Fconvert%2F%7Bfileextension%7D) | Client submits raw bytes plus a route-supplied extension | `ConvertController.Convert(byte[] file, string fileExtension, PdfFormat format)` | Same rule set as OP-CONVERT-REQUEST |
| [OP-EXTRACT-PAGES](operations/op-extract-pages.md) | Extract pages | [`POST v1/extract`](endpoints/extract-controller.md#post-v1%2Fextract) | Client submits an `ExtractPagesRequest` | `ExtractController.Extract(ExtractPagesRequest)` | [BR-PDFAPI-004](business-rules.md#br-pdfapi-004-extraction-requires-pdf-validation), [BR-PDFAPI-005](business-rules.md#br-pdfapi-005-pdf-validity-by-file-signature), [BR-PDFAPI-010](business-rules.md#br-pdfapi-010-tracking-forced-on-with-heat-email), [BR-PDFAPI-016](business-rules.md#br-pdfapi-016-save-input-to-temp-storage), [BR-PDFAPI-017](business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult), [BR-PDFAPI-018](business-rules.md#br-pdfapi-018-page-range-clamping-and-reversal) |
| [OP-MERGE-DOCUMENTS](operations/op-merge-documents.md) | Merge documents | [`POST v1/merge`](endpoints/merge-controller.md#post-v1%2Fmerge) | Client submits a `MergeRequest` | `MergeController.Merge(MergeRequest)` | [BR-PDFAPI-001](business-rules.md#br-pdfapi-001-null-merge-request-bypasses-the-error-envelope), [BR-PDFAPI-002](business-rules.md#br-pdfapi-002-default-merge-options-substitution), [BR-PDFAPI-006](business-rules.md#br-pdfapi-006-merge-aborts-entirely-on-pre-conversion-failure), [BR-PDFAPI-007](business-rules.md#br-pdfapi-007-pdf-a-output-silently-downgraded), [BR-PDFAPI-010](business-rules.md#br-pdfapi-010-tracking-forced-on-with-heat-email), [BR-PDFAPI-016](business-rules.md#br-pdfapi-016-save-input-to-temp-storage), [BR-PDFAPI-017](business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult), [BR-PDFAPI-020](business-rules.md#br-pdfapi-020-activepdf-retry-behavior) |
| [OP-DOWNLOAD-BY-TRACKING-ID](operations/op-download-by-tracking-id.md) | Download by tracking id | [`GET v1/legacy/download/{trackingId}`](endpoints/legacy-controller.md#get-v1%2Flegacy%2Fdownload%2F%7Btrackingid%7D) | Client requests a tracked document | `LegacyController.Download(long)` | [BR-PDFAPI-013](business-rules.md#br-pdfapi-013-download-requires-succeeded-status-and-output-path), [BR-PDFAPI-017](business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult) |
| [OP-CHECK-TRACKING-STATUS](operations/op-check-tracking-status.md) | Check tracking status | [`GET v1/info/track/{trackingId}`](endpoints/info-controller.md#get-v1%2Finfo%2Ftrack%2F%7Btrackingid%7D) | Client polls a tracked request | `InfoController.CheckPdfTrackingStatus(long, int, int)` | [BR-PDFAPI-011](business-rules.md#br-pdfapi-011-tracking-status-lifecycle), [BR-PDFAPI-012](business-rules.md#br-pdfapi-012-tracking-degrades-gracefully-without-a-unit-of-work), [BR-PDFAPI-014](business-rules.md#br-pdfapi-014-status-check-polling-loop) |
| [OP-GET-PAGE-COUNT](operations/op-get-page-count.md) | Get page count | [`POST v1/info/pages/count`](endpoints/info-controller.md#post-v1%2Finfo%2Fpages%2Fcount) | Client submits PDF bytes | `InfoController.GetPageCount(byte[])` | [BR-PDFAPI-005](business-rules.md#br-pdfapi-005-pdf-validity-by-file-signature) |
| [OP-HAS-FORM-FIELDS](operations/op-has-form-fields.md) | Has form fields | [`POST v1/info/fields/exist`](endpoints/info-controller.md#post-v1%2Finfo%2Ffields%2Fexist) | Client submits PDF bytes | `InfoController.HasFormFields(byte[], bool)` | [BR-PDFAPI-005](business-rules.md#br-pdfapi-005-pdf-validity-by-file-signature), [BR-PDFAPI-021](business-rules.md#br-pdfapi-021-form-field-inspection-client-selection) |
| [OP-FLATTEN-FORM-FIELDS](operations/op-flatten-form-fields.md) | Flatten form fields | [`POST v1/info/fields/flatten`](endpoints/info-controller.md#post-v1%2Finfo%2Ffields%2Fflatten) | Client submits PDF bytes | `InfoController.FlattenFormFields(byte[], bool)` | [BR-PDFAPI-005](business-rules.md#br-pdfapi-005-pdf-validity-by-file-signature), [BR-PDFAPI-021](business-rules.md#br-pdfapi-021-form-field-inspection-client-selection) |
| [OP-IS-PDF](operations/op-is-pdf.md) | Validate is-PDF | [`POST v1/info/validate`](endpoints/info-controller.md#post-v1%2Finfo%2Fvalidate) | Client submits arbitrary bytes | `InfoController.IsPdf(byte[])` | [BR-PDFAPI-005](business-rules.md#br-pdfapi-005-pdf-validity-by-file-signature) |
| [OP-VALIDATE-PDFA](operations/op-validate-pdfa.md) | Validate PDF/A conformance | [`POST v1/info/validate/pdfa`](endpoints/info-controller.md#post-v1%2Finfo%2Fvalidate%2Fpdfa) | Client submits PDF bytes | `InfoController.IsPdfa(byte[])` | None catalogued — inspection-only logic |
| [OP-GET-PDF-VERSION](operations/op-get-pdf-version.md) | Get PDF version | [`POST v1/info/version`](endpoints/info-controller.md#post-v1%2Finfo%2Fversion) | Client submits PDF bytes | `InfoController.Version(byte[])` | [BR-PDFAPI-005](business-rules.md#br-pdfapi-005-pdf-validity-by-file-signature) |
| [OP-GET-BUILD-VERSION](operations/op-get-build-version.md) | Get build version | [`GET buildVersion`](endpoints/api-info-controller.md#get-buildversion) | Client requests deployment metadata | `ApiInfoController.GetBuildVersionData()` | None catalogued — no business logic |

## Cross-operation flow diagram

The following diagram shows how each of the 13 endpoints routes to its operation and where processor selection, tracking, and download decisions occur.

```mermaid
flowchart TD
    A["Request received"] --> B{"Which endpoint?"}
    B -->|convert| C["OP-CONVERT-REQUEST /<br>OP-CONVERT-FILE"]
    B -->|extract| D["OP-EXTRACT-PAGES"]
    B -->|merge| E["OP-MERGE-DOCUMENTS"]
    B -->|legacy download| F["OP-DOWNLOAD-BY-TRACKING-ID"]
    B -->|info track| G["OP-CHECK-TRACKING-STATUS"]
    B -->|info inspection| H["OP-GET-PAGE-COUNT / OP-HAS-FORM-FIELDS /<br>OP-FLATTEN-FORM-FIELDS / OP-IS-PDF /<br>OP-VALIDATE-PDFA / OP-GET-PDF-VERSION"]
    B -->|buildVersion| I["OP-GET-BUILD-VERSION"]
    C --> J["Processor selected<br>BR-PDFAPI-003"]
    J --> K["Tracking record created/updated"]
    D --> K
    E --> K
    K --> L["Ok result with PdfResult"]
    F --> M{"Status Succeeded and<br>OutputFilePath set?"}
    M -->|Yes| N["Document returned"]
    M -->|No| O["Failure PdfResult, 200 OK"]
    G --> P["Tracking row read; optional poll loop"]
    H --> Q["No tracking, no database<br>pure inspection"]
    I --> R["Build metadata from file system"]
```

## Transaction boundaries

| Operation | Unit of work | Commit point | Rollback trigger |
| --- | --- | --- | --- |
| [OP-CONVERT-REQUEST](operations/op-convert-request.md) | `IUnitOfWorkFactory("oracle")`, `InstancePerRequest` | `PdfTrackingService.CreateTrackingRecord` and `UpdateTrackingRecord`, each bracketed by `_uow.Begin()`/`_uow.Commit()` | Unhandled exception before `Commit()`; NHibernate exception during flush |
| [OP-CONVERT-FILE](operations/op-convert-file.md) | Same as OP-CONVERT-REQUEST | Same as OP-CONVERT-REQUEST | Same as OP-CONVERT-REQUEST |
| [OP-EXTRACT-PAGES](operations/op-extract-pages.md) | Same as OP-CONVERT-REQUEST | Same as OP-CONVERT-REQUEST | Same as OP-CONVERT-REQUEST |
| [OP-MERGE-DOCUMENTS](operations/op-merge-documents.md) | Same as OP-CONVERT-REQUEST | Same as OP-CONVERT-REQUEST | Same as OP-CONVERT-REQUEST |
| [OP-DOWNLOAD-BY-TRACKING-ID](operations/op-download-by-tracking-id.md) | `IUnitOfWorkFactory("oracle")`, `InstancePerRequest` (read-only) | No write — read-only `Query()` inside `Begin()`/`Commit()` | Not applicable — no write occurs |
| [OP-CHECK-TRACKING-STATUS](operations/op-check-tracking-status.md) | `IUnitOfWorkFactory("oracle")`, `InstancePerRequest` (read-only) | No write — read-only `Query()` inside `Begin()`/`Commit()` | Not applicable — no write occurs |
| [OP-GET-PAGE-COUNT](operations/op-get-page-count.md) | None | Not applicable — no database access | Not applicable |
| [OP-HAS-FORM-FIELDS](operations/op-has-form-fields.md) | None | Not applicable | Not applicable |
| [OP-FLATTEN-FORM-FIELDS](operations/op-flatten-form-fields.md) | None | Not applicable | Not applicable |
| [OP-IS-PDF](operations/op-is-pdf.md) | None | Not applicable | Not applicable |
| [OP-VALIDATE-PDFA](operations/op-validate-pdfa.md) | None | Not applicable | Not applicable |
| [OP-GET-PDF-VERSION](operations/op-get-pdf-version.md) | None | Not applicable | Not applicable |
| [OP-GET-BUILD-VERSION](operations/op-get-build-version.md) | None | Not applicable | Not applicable |

## Failure and edge-case behavior

- Convert, extract, merge, and download failures are caught in the action and returned as a `PdfResult` with `200 OK` — the caller must inspect `Status`/`Message` ([BR-PDFAPI-017](business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult)).
- The six `v1/info/*` byte-array inspection endpoints and `v1/info/track/{trackingId}` have no `try`/`catch`; an unhandled exception (e.g. `PdfException` for a non-PDF payload) produces framework exception detail (`IncludeErrorDetailPolicy.Always`) before `ApiResponseHandler` runs — the final client-visible envelope is unknown** (see [Endpoints: Error response shape](endpoints.md#error-response-shape)).
- A null `MergeRequest` body fails as a framework error, bypassing the per-action envelope entirely ([BR-PDFAPI-001](business-rules.md#br-pdfapi-001-null-merge-request-bypasses-the-error-envelope)).
- An unrecognized convert file extension produces a failure `PdfResult` whose `Status` is left at the enum default (`NotTracked`), not `Failed` — callers filtering strictly on `Status == Failed` will miss this case ([BR-PDFAPI-008](business-rules.md#br-pdfapi-008-unsupported-extension-leaves-status-at-default)).
- When tracking persistence is unavailable (`_uow == null`), tracking operations degrade gracefully rather than failing the request ([BR-PDFAPI-012](business-rules.md#br-pdfapi-012-tracking-degrades-gracefully-without-a-unit-of-work)).

## Related documentation
- [API index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Endpoints](endpoints.md)
- [Authentication and authorization](authentication-authorization.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Business rules](business-rules.md)
- [Data model](data-model.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with `**` could not be confirmed; treat as unknown until verified.

## Sources
- PdfAPI\Controllers\v1\ConvertController.cs
- PdfAPI\Controllers\v1\ExtractController.cs
- PdfAPI\Controllers\v1\MergeController.cs
- PdfAPI\Controllers\v1\LegacyController.cs
- PdfAPI\Controllers\v1\InfoController.cs
- PdfAPI\Controllers\v1\ApiInfoController.cs
- PdfAPI\Services\PdfTrackingService.cs
- PdfAPI\App_Start\IocConfig.cs
